/**
 * Class Main
 * 
 * @author Hussein Patwa
 * @date 20 April 2008 - Rev 09 May 2008
 * @version 4.0 The Main initializer class for the entire application
 */
package trend;

import java.util.*;
import java.io.*;

@SuppressWarnings("all")
public class Main {
  /**
   * Constructor for Main
   * 
   * @param spatialobject An array of spatialobject objects
   * @param Neighbourhood An instance of the neighbourhood information
   */
  ArrayList<Spatialobject> spatialObjectList = new ArrayList<Spatialobject>();
  NeighbourhoodInfo neighbourhood;

  public Main(String start_area_name, int minlength, int maxlength,
      double min_confidence) {
    /**
     * Instance of main
     * 
     * @param start_area_name Name of the area to start trend detection
     * @param minLength Length below which trend remains undefined
     * @param maxLength Length above which trend is assumed
     * @param min_conf Minimum confidence value for alignment similarity
     */
    // Read the data file into the program
    Csvinput datafile = new Csvinput(new File("data.csv"), 50, 6);
    String[][] values = datafile.getValues();
    for (int i = 0; i < datafile.getNumberOfRows(); i++) {
      Spatialobject so = new Spatialobject(values[i][2], new Double(
          values[i][3]).doubleValue(), new Double(values[i][4])
          .doubleValue(), new Double(values[i][5]).doubleValue());
      spatialObjectList.add(so);
    }
    // normalize the data in spatialObjectList because the scale on X, Y
    // and V are quite different
    spatialObjectList = normalize(spatialObjectList);
    // read the neighbourhood data
    Vector matdata = new Vector();
    datafile = new Csvinput(new File("abdnMat.csv"), 50, 50);
    values = datafile.getValues();
    for (int i = 0; i < datafile.getNumberOfRows(); i++) {
      Vector row = new Vector();
      for (int j = 0; j < datafile.getNumberOfColumns(); j++) {
        double tmp = new Double(values[i][j]).doubleValue();
        row.add(tmp);
      }
      matdata.add(row);
    }
    neighbourhood = new NeighbourhoodInfo(matdata);
    // call Local trending

    int index = getIndex(start_area_name);
    if (index != -1) {
      Local ltrend = new Local(neighbourhood, spatialObjectList, index,
          minlength, maxlength, min_confidence);
      ltrend.viewTrends();

      Global gtrend = new Global(neighbourhood, spatialObjectList,
          index, minlength, maxlength, min_confidence);
      gtrend.viewTrends();
    }
  }

  ArrayList normalize(ArrayList lst) {
    // x, y and w columns are normalized
    Vector x = new Vector(), y = new Vector(), v = new Vector();
    for (int j = 0; j < lst.size(); j++) {
      Spatialobject temp = (Spatialobject) lst.get(j);
      x.add(temp.getX());
      y.add(temp.getY());
      v.add(temp.getV());
    }
    double meanX = mean(x), meanY = mean(y), meanV = mean(v);

    double lsX = lS(x), lsY = lS(y), lsV = lS(v);

    for (int j = 0; j < lst.size(); j++) {
      Spatialobject temp = (Spatialobject) lst.get(j);
      temp.setX((temp.getX() - meanX) / lsX);
      temp.setY((temp.getY() - meanY) / lsY);
      temp.setV((temp.getV() - meanV) / lsV);
    }
    return lst;
  }

  /**
   * Map names to their numerical indices
   * 
   * @param name Name of the area matching the index
   * @return int
   */
  int getIndex(String name) {
    int i = 0;
    for (Spatialobject o : spatialObjectList) {
      if (name.compareTo(o.getName()) == 0)
        return i;
      else
        i++;
    }
    return -1;
  }

  static public double mean(Collection buffer) {
    Vector list = new Vector(buffer);
    int size = buffer.size();
    double sum = 0;
    for (int i = 0; i < size; i++) {
      Double x = (Double) list.elementAt(i);
      sum = sum + x.doubleValue();
    }
    return (sum / size);
  }

  static public double lS(Collection buffer) {
    double avg = mean(buffer);
    Vector list = new Vector(buffer);
    int size = buffer.size();
    double sum = 0;
    double deviation = 0;
    for (int i = 0; i < size; i++) {
      Double x = (Double) list.elementAt(i);
      deviation = x.doubleValue() - avg;
      sum = sum + (deviation * deviation);
    }
    return (Math.sqrt(sum / (size - 1)));
  }

  /**
   * Starter method for the main application
   * 
   * @param args Arguments from the command line
   */
  public static void main(String[] args) {
    if (args.length == 4) {
      int minimum_length = (new Integer(args[1])).intValue();
      int maximum_length = (new Integer(args[2])).intValue();
      double minimum_confidence = (new Double(args[3])).doubleValue();
      new Main(args[0], minimum_length, maximum_length,
          minimum_confidence);
    } else
      System.out
          .println("Please enter the arguments -- start_area_name, minimum_length, maximum_length and minimum_confidence");
  }
}
